package main

import "fmt"

func main() {
	// slice 的原理
	// 1. 第一个现象
	testA := make([]int, 0)
	testB := []int{1, 2, 3}
	fmt.Println(copy(testA, testB)) // 不会去主动扩展testA 的空间 长度要跟testB 设置成为一样才行
	fmt.Println(testA)

	// 2. 第二个现象
	testC := testB[:]
	testC[0] = 8 //影响原数组
	fmt.Println(testB)
	fmt.Println(testC) // 底层都是指向的同一块内存

	// 3、第三个现象
	testC = append(testC, 9) // 会导致原来的数组扩充  触发了扩容机制，切片会指向新的内存地址
	fmt.Println(testB)       // append 函数不影响原来的数组
	fmt.Println(testC)
	testC[0] = 100
	fmt.Println(testB) //  不会变
	fmt.Println(testC) // 会变

	//4.第四个现象
	fmt.Println(cap(testC)) // 6     扩了一倍
	fmt.Println(len(testC)) // 4

	// 切片底层是使用数组实现的， 既要使用数组又要满足动态的功能

	//1 使用make 方法初始化 len cap 是多少
	d := make([]int, 5, 6) // make(类型，长度，容量)
	// ptr *Elem 指针指向真实的数据
	fmt.Printf("len=%d,cap=%d\n", len(d), cap(d))

	// 通过数组取切片
	data := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	testS := data[2:4]
	testS1 := data[3:6]
	for index, value := range testS {
		fmt.Println(index, value)
	}
	fmt.Printf("len=%d,cap=%d\n", len(testS), cap(testS))
	fmt.Printf("len=%d,cap=%d\n", len(testS1), cap(testS1))

	//3
	testS2 := []int{1, 2, 3}
	fmt.Println(testS2)

	// 切片的扩容问题
	// 当数据添加的长度大于原有数组的时候
	// 扩容阶段会影响速度 Python list 底层实际上也是数组，也会面临数组动态扩容，
	// python 中的list 数据类型可以不一样

	oldSlice := make([]int, 0)
	fmt.Printf("len=%d,cap=%d\n", len(oldSlice), cap(oldSlice))
	oldSlice = append(oldSlice, 1)
	fmt.Printf("len=%d,cap=%d\n", len(oldSlice), cap(oldSlice))
	oldSlice = append(oldSlice, 1)
	fmt.Printf("len=%d,cap=%d\n", len(oldSlice), cap(oldSlice))
	oldSlice = append(oldSlice, 1)
	fmt.Printf("len=%d,cap=%d\n", len(oldSlice), cap(oldSlice))

	/*
		Go 中切片扩容的策略是这样的：

		首先判断，如果新申请容量（cap）大于2倍的旧容量（old.cap），最终容量（newcap）就是新申请的容量（cap）
		否则判断，如果旧切片的长度小于1024，则最终容量(newcap)就是旧容量(old.cap)的两倍，即（newcap=doublecap）
		否则判断，如果旧切片长度大于等于1024，则最终容量（newcap）从旧容量（old.cap）开始循环增加原来的 1/4，
		即（newcap=old.cap,for {newcap += newcap/4}）直到最终容量（newcap）大于等于新申请的容量(cap)，即（newcap >= cap）
		如果最终容量（cap）计算值溢出，则最终容量（cap）就是新申请容量（cap）
	*/
	//如果小于1024 扩容的速度是2倍 如果大于了1024 扩容的速度就是1.25
	//切片来说 1. 底层是数组，如果是基于数组产生的 会有一个问题就是会影响原来的数组。
	//3. 切片的传递是引用传递

	oldArr := [3]int{1, 2, 3}
	newArr := oldArr
	newArr[0] = 5
	fmt.Println(newArr, oldArr) // 数组是值传递

	oldTestSlice := []int{1, 2, 3}
	newTestSlice := oldTestSlice
	newTestSlice[0] = 5
	fmt.Println(oldTestSlice, newTestSlice) // 引用传递

	//go语言中slice的原理讲解很重要，这个有坑（对于初学者），有经验的程序员觉得这个不是坑
	//程序员也是消费者-java c++ go -静态语言是站在对处理器的角度考虑， python - 才会站在使用者的角度上去考虑，对于处理器就不友好
	//当make遇到了append容易出现的坑

	testSliceC := make([]int, 5) // 一旦加了数字就不是空的 会有默认的初始值
	testSliceC = append(testSliceC, 6)
	fmt.Println(testSliceC) // [0 0 0 0 0 6]

}
